package game_frame

import (
	"fmt"
	"gamesdk/common/log"
	"gamesdk/define"
	"gamesdk/global"
	"gamesdk/msg"
	"sync"
	"time"

	"github.com/golang/protobuf/proto"
)

//匹配

type MatchMsg struct {
	client *Client
	match  *msg.S2CCmdMatch
}

type Match struct {
	match     chan *MatchMsg
	exit      chan bool
	room      *Room
	waitGroup sync.WaitGroup
}

func NewMatch(room *Room) *Match {
	defer log.Trace()()
	match := &Match{
		match: make(chan *MatchMsg, global.G_Config.TableNum),
		exit:  make(chan bool),
		room:  room,
	}
	go match.Run()
	return match
}

func (this *Match) Run() {
	defer log.Warn("结束匹配逻辑")
	this.waitGroup.Add(1)
	defer this.waitGroup.Done()
	for {
		match := <-this.match
		if match == nil {
			return
		}
		this.Match(match)
	}
}
func (this *Match) Exit() {
	defer log.Trace()()
	close(this.match)
}

//开始匹配
func (this *Match) Start(match *MatchMsg) {
	defer log.Trace()()
	this.match <- match
}

// //匹配结束
func (this *Match) End(user *User, c2sMatch *msg.C2SCmdMatch) {
	defer log.Trace()()
	buffer, err := proto.Marshal(c2sMatch)
	if err != nil {
		log.Error(err.Error())
		return
	}
	user.funcSendMsg(int32(msg.CMDKIND_MATCH), c2sMatch.UserId, buffer)
}

//断线重连
func (this *Match) OfflineMatch(user *User, match *msg.S2CCmdMatch, c2sMatch *msg.C2SCmdMatch) {
	defer log.Trace()()
	//重新连接直接放置
	tableId := user.GetTableId()
	if tableId > -1 {
		table := this.room.tableManager.GetTableById(tableId)
		if table.waitInit {
			log.Warn("本房间已经关闭 id:%d room:%d", table.id, table.roomID)
			goto A
		}
		chairId := user.GetChairId()
		msgMatchChan := &MsgMatchChan{
			user:                 user,
			roomId:               int64(match.Room.RoomId),
			roomProb:             match.Roomctl,
			level:                match.Room.Level,
			roomRate:             int64(match.Room.RoomRate),
			entranceRestrictions: match.Room.EntranceRestrictions,
			adviceConfig:         match.Room.AdviceConfig,
			chairId:              chairId,
			result:               make(chan *MatchResult),
			isOpenAiRobot:        match.Room.IsOpenAiRobot,
		}
		log.Info("开始逻辑匹配%d", user.GetId())
		table.SendMatchMsg(msgMatchChan)
		result := <-msgMatchChan.result
		log.Info("逻辑匹配完成%d", user.GetId())
		//安排好了桌子
		if result.ok == define.SIT_DOWN_OK {
			c2sMatch.ChairNum = int32(result.chairId)
			c2sMatch.TableNum = int32(result.tableId)
		}
		c2sMatch.Result = int32(result.ok)
	} else {
		log.Warn("%d用户重连没有带桌子id %v", user.GetId(), match)
	}
A:
	if c2sMatch.Result == int32(define.SIT_DOWN_OK) {
		log.UserInfoLog(match.UserId, "用户重连匹配成功 TableNum:%d,ChairNum:%d, roomId:%d", c2sMatch.TableNum, c2sMatch.ChairNum, match.Room.RoomId)
		log.Info("%d用户匹配成功 TableNum:%d,ChairNum:%d,roomId:%d", match.UserId, c2sMatch.TableNum, c2sMatch.ChairNum, match.Room.RoomId)
	} else {
		log.UserInfoLog(match.UserId, "用户重连匹配失败,roomid:%d", match.Room.RoomId)
		log.Error("匹配失败 user:%d %v", match.UserId, match)
		this.End(user, c2sMatch)
		user.EXit()
	}
}

func (this *Match) OnlineMatch(user *User, match *msg.S2CCmdMatch, c2sMatch *msg.C2SCmdMatch) {
	defer log.Trace()()
	if global.G_Config.GameType == 1 || global.G_Config.GameType == 3 {
		tableId, ok := this.room.openRoom.Load(fmt.Sprintf("%d-%d", match.PlatformId, match.Room.RoomId))
		if ok {
			match.TableId = int64(tableId.(int32))
			if match.TableId < 0 {
				log.Error("百人场已经启动，但是获取的tableid 小于0 %d", match.Room.RoomId)
				goto A
			}
		} else {
			log.Info("开始启动百人场房间%d", match.Room.RoomId)
		}

	}
	//查看是不是指定位置
	if match.TableId >= 0 {
		if match.Room == nil {
			log.Warn("match room is nil")
		} else {
			table := this.room.tableManager.GetTableById(int(match.TableId))
			if table.platformId >= 0 {
				if user.platformId != table.platformId {
					log.Debug("平台ID不相等用户%d要进入%d平台，当前平台%d", user.GetId(), user.platformId, table.platformId)
					goto A
				}
			}
			if table.roomID >= 0 {
				if user.roomId != table.roomID {
					log.Debug("房间ID不相等用户%d要进入%d房间，当前房间%d", user.GetId(), user.roomId, table.roomID)
					goto A
				}
			}
			if table.waitInit {
				log.Warn("初始化逻辑中，直接匹配下一桌 id:%d room:%d", table.id, table.roomID)
				goto A
			}
			if table.isReset == true {
				log.Warn("房间重制中，不能匹配 id:%d room:%d", table.id, table.roomID)
				goto A
			}
			//判断入场条件是否到达
			if table.adviceConfig != "" && table.adviceConfig != match.Room.AdviceConfig {
				log.Debug("房间%d配置不相等，旧:%s-----新:%s", table.roomID, table.adviceConfig, match.Room.AdviceConfig)
				goto A
			}
			if table.entranceRestrictions != -1 && table.entranceRestrictions != match.Room.EntranceRestrictions {
				log.Debug("房间%d进入条件不相等， 旧:%d-----新:%d", table.roomID, table.entranceRestrictions, match.Room.EntranceRestrictions)
				goto A
			}
			// if table.level != 0 && table.level != match.Room.Level {
			// 	log.Debug("房间%d,等级配置不相等，旧:%d-----新:%d", table.roomID, table.level, match.Room.Level)
			// 	goto A
			// }
			// if table.roomRate != 0 && table.roomRate != int64(match.Room.RoomRate) {
			// 	log.Debug("房间%d,roomRate不相等，旧:%d-----新:%d", table.roomID, table.roomRate, match.Room.RoomRate)
			// 	goto A
			// }
			//判断是否开始
			if table.count >= table.max {
				log.Debug("%d人数已经达到上线%d:%d(uid:=)", table.roomID, table.id, table.count, user.GetId())
				goto A
			}
			if match.Balance < match.Room.EntranceRestrictions {
				log.Debug("%d入场金额不正确%d", table.roomID, user.GetId())
				goto A
			}
			msgMatchChan := &MsgMatchChan{
				user:                 user,
				roomId:               int64(match.Room.RoomId),
				roomProb:             match.Roomctl,
				level:                match.Room.Level,
				roomRate:             int64(match.Room.RoomRate),
				entranceRestrictions: match.Room.EntranceRestrictions,
				adviceConfig:         match.Room.AdviceConfig,
				chairId:              -1,
				result:               make(chan *MatchResult),
				isOpenAiRobot:        match.Room.IsOpenAiRobot,
			}
			log.Info("开始逻辑匹配%d", user.GetId())
			table.SendMatchMsg(msgMatchChan)
			result := <-msgMatchChan.result
			log.Info("逻辑匹配完成%d", user.GetId())

			if result.ok == define.SIT_DOWN_OK {
				c2sMatch.ChairNum = int32(result.chairId)
				c2sMatch.TableNum = int32(result.tableId)
				c2sMatch.Result = int32(define.SIT_DOWN_OK)
				goto A
			} else if result.ok == define.SIT_DOWN_ERROR_OVER {
				c2sMatch.Result = int32(define.SIT_DOWN_ERROR_OVER)
				goto A
			} else {
				c2sMatch.Result = int32(define.SIT_DOWN_ERROR_NORMAL)
				goto A
			}
		}
	} else {
		//遍历所有桌子
		this.room.tableManager.Traverse(func(key int, table *Table) bool {
			if match.Room == nil {
				log.Warn("match room is nil")
				return false
			}

			if table.platformId >= 0 {
				if user.platformId != table.platformId {
					log.Debug("平台ID不相等用户%d要进入%d平台，当前平台%d", user.GetId(), user.platformId, table.platformId)
					return true
				}
			}
			if table.roomID >= 0 {
				if user.roomId != table.roomID {
					log.Debug("房间ID不相等用户%d要进入%d房间，当前房间%d", user.GetId(), user.roomId, table.roomID)
					return true
				}
			}
			ret := true
			//百人场
			if global.G_Config.GameType == 1 || global.G_Config.GameType == 3 {
				ret = false
			}

			if table.waitInit {
				log.Warn("初始化逻辑中，直接匹配下一桌 id:%d room:%d", table.id, table.roomID)
				return ret
			}
			if table.isReset == true {
				log.Warn("房间重制中，不能匹配 id:%d room:%d", table.id, table.roomID)
				return ret
			}
			//判断入场条件是否到达
			if table.adviceConfig != "" && table.adviceConfig != match.Room.AdviceConfig {
				log.Warn("房间%d配置不相等，旧:%s-----新:%s", table.roomID, table.adviceConfig, match.Room.AdviceConfig)
				return ret
			}
			if table.entranceRestrictions != -1 && table.entranceRestrictions != match.Room.EntranceRestrictions {
				log.Warn("房间%d进入条件不相等， 旧:%d-----新:%d", table.roomID, table.entranceRestrictions, match.Room.EntranceRestrictions)
				return ret
			}
			//判断是否开始
			if table.count >= table.max {
				log.Warn("%d人数已经达到上线%d:%d", table.roomID, user.GetId(), table.count)
				return ret
			}
			if match.Balance < match.Room.EntranceRestrictions {
				log.Warn("%d入场金额不正确%d", table.roomID, user.GetId())
				return false
			}
			msgMatchChan := &MsgMatchChan{
				user:                 user,
				roomId:               int64(match.Room.RoomId),
				roomProb:             match.Roomctl,
				level:                match.Room.Level,
				roomRate:             int64(match.Room.RoomRate),
				entranceRestrictions: match.Room.EntranceRestrictions,
				adviceConfig:         match.Room.AdviceConfig,
				chairId:              -1,
				result:               make(chan *MatchResult),
				isOpenAiRobot:        match.Room.IsOpenAiRobot,
			}

			table.SendMatchMsg(msgMatchChan)
			result := <-msgMatchChan.result
			c2sMatch.Result = int32(result.ok)
			//安排好了桌子
			if result.ok == define.SIT_DOWN_OK {
				c2sMatch.ChairNum = int32(result.chairId)
				c2sMatch.TableNum = int32(result.tableId)
				close(msgMatchChan.result)
				return false
			}
			if result.ok == define.SIT_DOWN_ERROR_OVER {
				close(msgMatchChan.result)
				return false
			}
			close(msgMatchChan.result)
			return true
		})
	}
A:

	if c2sMatch.Result == int32(define.SIT_DOWN_OK) {
		log.UserInfoLog(match.UserId, "用户匹配成功 TableNum:%d,ChairNum:%d,roomId:%d", c2sMatch.TableNum, c2sMatch.ChairNum, match.Room.RoomId)
		log.Info("%d用户匹配成功 TableNum:%d,ChairNum:%d,roomId:%d", match.UserId, c2sMatch.TableNum, c2sMatch.ChairNum, match.Room.RoomId)
	} else {
		log.UserInfoLog(match.UserId, "用户匹配失败 roomId:%d", match.Room.RoomId)
		log.Error("匹配失败：user:%d %v", match.UserId, match)
		this.End(user, c2sMatch)
		user.EXit()
	}
}

/*
*用户匹配
 */
func (this *Match) Match(matchMsg *MatchMsg) {
	defer log.Trace()()

	match := matchMsg.match
	userId := match.UserId
	c2sMatch := &msg.C2SCmdMatch{
		UserId: userId,
		Result: int32(define.SIT_DOWN_ERROR_NORMAL),
	}
	log.Info("开始匹配%d", userId)
	//判断此用户是不是离线用户
	user := this.room.userManager.GetOfflineById(userId)
	if user == nil {
		//判断是不是用户是不是同一个用户
		u := this.room.userManager.GetById(userId)
		if u != nil {
			log.Warn("同一个用户禁止进入两次 %d", userId)
			buffer, err := proto.Marshal(c2sMatch)
			if err != nil {
				log.Error(err.Error())
				return
			}
			sendMsg := &msg.C2SNoticeMsg{Cmd: int32(msg.CMDKIND_MATCH), UserId: userId, Body: buffer, Token: this.room.token, MsgId: time.Now().UnixNano()}
			matchMsg.client.funcWrite(sendMsg)
			return
		}
		if match.Room == nil {
			log.Warn("房间不正确 %d", userId)
			buffer, err := proto.Marshal(c2sMatch)
			if err != nil {
				log.Error(err.Error())
				return
			}
			sendMsg := &msg.C2SNoticeMsg{Cmd: int32(msg.CMDKIND_MATCH), UserId: userId, Body: buffer, Token: this.room.token, MsgId: time.Now().UnixNano()}
			matchMsg.client.funcWrite(sendMsg)
			return
		}
		if match.IsRobot {
			user = NewRobot(matchMsg.client, userId, match.Uid, "token", 1, match.Nick, match.Account, match.Avatar, match.Sex, "sign", match.EquipmentCode, int(time.Now().Unix()), match.GameId, int64(match.Room.RoomId), match.GameName, match.Balance, match.PlatformId, match.City, match.Ip, this.room)
			//log.Debug("机器人进入 %v", match)
		} else {
			user = NewUser(matchMsg.client, userId, match.Uid, "token", 1, match.Nick, match.Account, match.Avatar, match.Sex, "sign", match.EquipmentCode, int(time.Now().Unix()), match.GameId, int64(match.Room.RoomId), match.GameName, match.Balance, match.PlatformId, match.Pointctl, match.City, match.Ip, this.room)
			log.Debug("用户进入 %v", match)
		}
		user.prob = match.Pointctl
		user.balance = match.Balance
		this.OnlineMatch(user, match, c2sMatch)
	} else {
		user.prob = match.Pointctl
		user.SetStatus(g_UserStand)

		this.OfflineMatch(user, match, c2sMatch)
	}
}
